﻿using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using WCS_Entity.Model;
using WCS_Entity.Prorocol;
using WCS_Service.DomianService.Interface;
using WCS_Utility.ConstString;
using WCS_Utility.Extensions;
using WCS_Utility.Helper;

namespace WCS_Service.DomianService
{
    /// <summary>
    /// Tcp通信服务
    /// </summary>
    public class TcpComDomainManage : IComBaseDomainManage
    {
        public string comPara { get; set; }
        public List<ProtocolEntity> protocolPara { get; set; } = new List<ProtocolEntity>();
        public string serviceName { get; set; }
        public int autoEquipmentId { get; set; }

        public ConcurrentDictionary<string, ProtocolModel> protocolMsgList { get; set; } = new ConcurrentDictionary<string, ProtocolModel>();

        private string gengricMsg = "";

        private TcpClient tcpClient;

        private TcpComParaModel tcpComParaModel = new TcpComParaModel();

        public async Task<bool> ConnectAsync()
        {
            if (string.IsNullOrEmpty(comPara))
            {
                Log.Error("通信参数为空");
                return false;
            }
            return await Task.Run(() => 
            { 
                return true;
            });
        }
        public async Task<bool> InitService()
        {
            if (protocolPara is null || !protocolPara.Any())
            {
                Log.Error($"协议报文为空!");
                return false;
            }
            if (!await InitProtocolMsgAsync())
            {
                Log.Error($"协议报文初期化失败!");
                return false;
            }
            try
            {
                tcpClient = new TcpClient();
                tcpComParaModel = JsonConvert.DeserializeObject<TcpComParaModel>(comPara);
                await tcpClient.ConnectAsync(tcpComParaModel.ip, tcpComParaModel.port);
            }
            catch (Exception ex) 
            {
                Log.Error($"TCP{tcpComParaModel.ip}连接异常{ex.Message}!");
            }
            return true;
        }
        public async Task<bool> DisConnectAsync()
        {
            if (tcpClient is not null)
            {
                return false;
            }
            return false;
        }
        public Task<string> ReceiveAsync()
        {
            throw new NotImplementedException();
        }

        public Task<bool> SendAsync(string para)
        {
            throw new NotImplementedException();
        }

        #region private
        private async Task<bool> InitProtocolMsgAsync()
        {
            var gengricInfo = protocolPara.Where(p => p.isGenericInfo)?.ToList();
            //协议通用字段处理
            if (gengricInfo is not null && gengricInfo.Any())
            {
                await GengricMsgProcessAsync(gengricInfo);
            }
            var msgInfo = protocolPara.Where(m => !m.isGenericInfo)?.GroupBy(msg => msg.messageType).ToList();
            if (msgInfo is null)
            {
                return false;
            }
            List<Task<bool>> processFlagList = new List<Task<bool>>();
            msgInfo.ForEach(info => 
            {
                processFlagList.Add(ProtocolMsgProcessAsync(info));
            });
            await Task.WhenAll(processFlagList);
            var flags = processFlagList.Select(p => p.Result).ToList();
            foreach (var item in flags)
            {
                if (!item)
                {
                    return false;
                }
            }
            return true;
        }
        private async Task GengricMsgProcessAsync(List<ProtocolEntity> infos)
        {
            await Task.Run(() => 
            {
                var infoList = infos.OrderBy(info => info.fieldIndex);
                int preIndex = 0;
                StringBuilder msg = new StringBuilder();
                foreach (var info in infoList) 
                {
                    if (CommonHelper.ContinuousNumberChecker(preIndex, info.fieldIndex,out int differenceNum))
                    {
                        msg.Append(info.fieldInfo+',');
                        preIndex ++;
                    }
                    else
                    {
                        msg.Append(CommonHelper.GetInsertChar(differenceNum - 1, ConstStringData.InsertStringInfo));
                        msg.Append(info.fieldInfo+',');
                        preIndex += differenceNum - 1;
                    }
                }
                gengricMsg = msg.ToString();
            });
        }

        /// <summary>
        /// 协议报文处理
        /// </summary>
        /// <param name="infos"></param>
        /// <returns></returns>
        private async Task<bool> ProtocolMsgProcessAsync(IGrouping<string,ProtocolEntity> infos)
        {
            if (!infos.Any())
            {
                return false;
            }
            List<Task<ProtocolModel>> dataMsg = new List<Task<ProtocolModel>>();
            
            //根据报文发送者分组
            var senderMsgList = infos.GroupBy(i => i.sender).ToList();
            senderMsgList.ForEach(s =>
            {
                dataMsg.Add(ProcotolMsgSenderProcessAsync(infos.Key, s.Key, s));
            });
            await Task.WhenAll(dataMsg);
            var protocolList = dataMsg.Select(s => s.Result)?.ToList();

            protocolList?.ForEach(p => 
            {
                protocolMsgList.TryAdd(string.Join('-',infos.Key,p.sender), p);
            });
            return true;
        }
        private async Task<ProtocolModel> ProcotolMsgSenderProcessAsync(string msgType,string sender, IGrouping<string, ProtocolEntity> infos)
        {
            ProtocolModel protocolModel = new ProtocolModel();
            protocolModel.sender = sender;
            protocolModel.functionCode = infos.Where(i => i.isFunctionCode).FirstOrDefault()?.fieldInfo.Split(":").Last();

            var dataMsgList = infos.GroupBy(i => i.fieldIndex).ToList();
            List<Task<MsgDataInfoModel>> dataMsgInfos = new List<Task<MsgDataInfoModel>>();
            dataMsgList.ForEach(d => 
            {
                dataMsgInfos.Add(ProtocolMsgSubProcessAsync(d));
            });
            await Task.WhenAll(dataMsgInfos);
            var dainfoList = dataMsgInfos.Select(d => d.Result).OrderBy(d => d.insertIndex).ToList();
            
            protocolModel.msgDataInfo = MontageMsgInfo(dainfoList);

            return protocolModel;
        }
        /// <summary>
        /// 合并在一帧数据中同一索引下的所有数据
        /// </summary>
        /// <param name="infos"></param>
        /// <returns></returns>
        private async Task<MsgDataInfoModel> ProtocolMsgSubProcessAsync(IGrouping<int, ProtocolEntity> infos)
        {
            MsgDataInfoModel result = new MsgDataInfoModel();
            List<Task<MsgDataInfoModel>> dataInfoList = new List<Task<MsgDataInfoModel>>();
            foreach (var item in infos)
            {
                dataInfoList.Add(DataInfoProcess(item.isBitAnalysis, item.fieldInfo, infos.Key));
            }
            await Task.WhenAll(dataInfoList);
            var dataInfo = dataInfoList.Select(d => d.Result).OrderBy(i => i.insertIndex).ToList();
            
            result.insertIndex = infos.Key;
            dataInfo.ForEach(d => 
            {
                result.info += d.info;
            });
            return result;
        }
        /// <summary>
        /// 报文内容处理
        /// </summary>
        /// <param name="isBitAnalysis"></param>
        /// <param name="info"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        private async Task<MsgDataInfoModel> DataInfoProcess(bool isBitAnalysis,string info,int startIndex)
        {
            MsgDataInfoModel result = new MsgDataInfoModel();
            await Task.Run(() => 
            {
                if (!info.Contains(":"))
                {
                    result.insertIndex = startIndex;
                    result.info = info;
                }
                else
                {
                    result = isBitAnalysis ? BitInfoProcess(info, startIndex) : InfoProcess(info, startIndex);
                }
            });
            return result;
        }
        /// <summary>
        /// 按位有效报文内容处理
        /// </summary>
        /// <param name="info"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        private MsgDataInfoModel BitInfoProcess(string info, int startIndex)
        {
            MsgDataInfoModel msgDataInfoModel = new MsgDataInfoModel();

            var index = info.Substring(0,info.IndexOf(':'));
            if (index is null)
            {
                Log.Error("数据异常");
                return null;
            }
            var bitInfos = info.Substring(info.IndexOf(':')+1).Split(new char[] { '{', ':', '}' }, StringSplitOptions.RemoveEmptyEntries);
            if (bitInfos is null || !BitInfoCheck(bitInfos,out var bitMsg))
            {
                Log.Error("位数据异常");
                return null;
            }
            var insertIndex = index.StringToIndex();
            if (!insertIndex.HasValue)
            {
                Log.Error("数据索引异常! ");
                return null;
            }
            msgDataInfoModel.insertIndex = startIndex + insertIndex.Value;
            msgDataInfoModel.info = bitMsg;
            return msgDataInfoModel;
        }

        private MsgDataInfoModel InfoProcess(string info, int startIndex)
        {
            MsgDataInfoModel msgDataInfoModel = new MsgDataInfoModel();
            var dataInfos = info.Split(':').ToList();
            if (dataInfos is null || dataInfos.Count != 2)
            {
                Log.Error("数据异常! ");
                return null;
            }
            var index = dataInfos.First().StringToIndex();
            if (!index.HasValue)
            {
                Log.Error("数据索引异常! ");
                return null;
            }
            msgDataInfoModel.insertIndex = index.Value + startIndex;
            msgDataInfoModel.info = dataInfos.LastOrDefault();
            return msgDataInfoModel;
        }
        private bool BitInfoCheck(string[] info,out string bitMsg)
        {
            bitMsg = "";
            foreach (var item in info)
            {
                if (item.Length!= 4)
                { 
                    return false;
                }
            }
            bitMsg = string.Join(null, info).BinaryToHex();
            return true;
        }
        /// <summary>
        /// 拼接报文内容
        /// </summary>
        /// <param name="infos"></param>
        /// <returns></returns>
        private string MontageMsgInfo(List<MsgDataInfoModel> infos)
        {
            string gengricInfo = gengricMsg;
            string result = "";
            if (string.IsNullOrEmpty(gengricMsg))
            {
                var msgInfos = infos.Select(i => i.info).ToList();
                result = string.Join(null, msgInfos);
                return result;
            }
            var msgInfoList = gengricInfo.Split(',').ToList();
            for (int i = 0; i < msgInfoList.Count; i++)
            {
                if (msgInfoList[i] == ConstStringData.InsertStringInfo)
                {
                    result += infos.Where(info => info.insertIndex == (i + 1))?.FirstOrDefault()?.info;
                    continue;
                }
                result += msgInfoList[i];
            }
            return result;
        }
        #endregion
    }
}
